Migrate from BotFramework to TeamsSDK#302
Conversation
Replace botbuilder/botframework-connector with @microsoft/teams.apps (TeamsSDK v2.0.6). Breaking changes: - Remove certificate auth (TeamsAuthCertificate) — use token or managedIdentityClientId instead - Env vars changed: TEAMS_APP_ID → CLIENT_ID, TEAMS_APP_PASSWORD → CLIENT_SECRET, TEAMS_APP_TENANT_ID → TENANT_ID - Reactions now work (addReaction/removeReaction) instead of throwing NotImplementedError - Graph API calls use @microsoft/teams.graph-endpoints typed endpoints Key changes: - BridgeHttpAdapter captures TeamsSDK route handler for serverless dispatch - Event handlers registered via app.on() (message, messageReaction, card.action, conversationUpdate, installationUpdate) - Outbound calls use app.send() and app.api.conversations.activities() - Stream support via post+edit (native HttpStream when SDK exports it) - Graph API uses typed endpoints from @microsoft/teams.graph-endpoints - isMention detection via activity entities instead of bot name matching Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Replace custom config fields with Pick<AppOptions, ...> clientId (was appId), clientSecret (was appPassword), tenantId (was appTenantId) - Remove TeamsAuthFederated, appType — use managedIdentityClientId directly - Constructor passes config through to App (App handles env var resolution) - Use this.app.id instead of this.config.appId for bot identity checks - 3 replay-fetch-messages tests have known failures (type shape mismatch) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Remove useless private api() getter, use this.app.api directly - Type handlers with specific activity types: handleMessageActivity(ctx: IActivityContext<IMessageActivity>) handleAdaptiveCardAction(ctx: IActivityContext<IAdaptiveCardActionInvokeActivity>) handleReactionFromContext(ctx: IActivityContext<IMessageReactionActivity>) - Remove unnecessary casts now that ctx.activity is properly typed Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Keep Azure OpenAI and DM handler changes as local-only, not part of the migration. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Keep only adapters.ts config changes, revert package.json dep changes. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
@heyitsaamir is attempting to deploy a commit to the Vercel Labs Team on Vercel. A member of the Team first needs to authorize it. |
- New env vars: CLIENT_ID, CLIENT_SECRET, TENANT_ID - New config: clientId, clientSecret, tenantId, token, managedIdentityClientId - Remove certificate auth docs (dropped) - Reactions now supported (add/remove) - Typing indicator now supported - Graph API uses @microsoft/teams.graph-endpoints - Note streaming and modals status Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This reverts commit 729fe46.
|
Hey @heyitsaamir! Thank you so much for this. Quick comment: would you be able to also add support for Task Modules? |
Yes! Would you like me to add that in this same pr or follow up? My plan was on a follow up. |
Split the 2,114-line index.ts into focused modules: - types.ts: TeamsAdapterConfig, TeamsThreadId, TeamsChannelContext - errors.ts: handleTeamsError as standalone pure function - graph-api.ts: TeamsGraphReader class with all Graph API read methods index.ts shrinks to ~1,133 lines, delegating graph reads to TeamsGraphReader which receives dependencies via constructor injection. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
|
@heyitsaamir I wasn't sure what they meant either, looked like spam or a bot—just deleted the comments to reduce noise. Thank you for the very detailed issue, I just replied to it for the sake of the PR thread being cleaner. It makes sense why modals support would need to be in a separate PR, since the underlying mechanics itself for how we handle modals would have to be tweaked slightly. Unrelated: does the Teams SDK have support for slash commands? That would be amazing if so. As the dream is for all adapters to be as close together as possible in terms of functionality. |
Sweet. I'm happy to put up a PR stacked on this, or once this goes in (if y'all are okay with it). As for slash commands - we currently have a version of it: The biggest downside with the current method is that in a group-chat, everyone sees the slash-message. In a DM it doesn't really matter that much. I will say that there are some more things coming soon that will enable better slash-command like experience soon. |
|
btw @bensabic I refactored a bit to split the giant index.ts into two files. Hope that's okay. The first file was just getting wildly unwieldy. |
bensabic
left a comment
There was a problem hiding this comment.
@heyitsaamir finally had a chance to formally review it.
The Teams SDK migration is directionally good, but this PR currently introduces a few blocking regressions and leaves the repo in a failing state.
-
The public adapter contract changes in a breaking way without a compatibility layer.
@chat-adapter/teamsis still on the 4.x line, but the exported config now switches fromappId/appPassword/appTenantId/TEAMS_APP_*toclientId/clientSecret/tenantId/CLIENT_*. Existing consumers will break on upgrade, and the examples/docs are still inconsistent about which env vars actually work. -
The PR currently breaks local typecheck/test surfaces.
packages/integration-testsfails typecheck because the replay helper still expectsappIdwhile several updated callers now passclientId, and the Teams-heavy replay/integration subset is also failing on this branch. That needs to be fixed before we can trust the migration coverage. -
Channel-thread history regresses for ordinary Teams channel traffic. The new channel-context caching only persists state when
channelData.team.aadGroupIdis already present, but the recorded payloads in this repo only carryteam.id. Without the old fallback/recovery path, thread-aware Graph reads fall back to the generic chat path instead of the proper channel-thread endpoints. -
WebhookOptionsare now stored on shared adapter state duringhandleWebhook(). Since the adapter instance is reused across requests, overlapping webhooks can overwrite each other’swaitUntilbefore the async handlers consume it. That is a real concurrency bug for production webhook handling. -
Outgoing reaction support is incomplete. Incoming Teams reactions are normalized into Chat emoji names like
thumbs_up, but outgoing reactions are sent back to Teams usingemoji.namedirectly. That means common flows like echoing a received reaction back will sendthumbs_upinstead of the Teams tokenlike. -
Env-only tenant autodetection does not fully reach proactive paths.
openDM()and channel-info logic still readthis.config.tenantId, but values resolved internally by the Teams SDK app are not copied back into adapter config. In practice, env-only setups can still fail until an inbound event has already cached tenant state.
Re: Modals, I'd say wait until this PR goes in, then we can cross that bridge when we come to it. Re: Slash commands, I'd ideally rather wait to add support for that until the Teams SDK has slash commands which are closer to Slack functionality. Mainly so the UX is more familiar to users and consistent across platforms. |
|
Ah thanks for the closer look! Yeah I called out the breaking options in the description, so I'm happy to build a translation layer between the two. Let me go through these suggestions, and get back to you :). Thanks Ben. |
Hello! I am the maintainer for TeamsSDK, which is the official SDK for Microsoft Teams. We noticed that y'all are using BotFramework in the adapter here which is actually now deprecated. We took the initiative to migrate you guys over to TeamsSDK. Hope that's okay!
Some wins:
Pending:
What didn't make it:
tokenoption (which is basically a factory that generates a token). Our general logic was that if someone is using certs, they might as well just use secrets.Some things I would like to add in a followup (or even in this):
Summary
Test plan
Tested the scenarios in the example bot.

Eg Channels:
DMs:

(Happy to share more screenshots / video if needed).